package code;


import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;

import main.ErrorException;
import main.WarningHandler;
import define.CodeOut;
import define.Config;
import define.ErrorDefine;
import define.ExcelType;
import define.ReferenceExtraType;
import define.ReferenceType;
import define.WarningDefine;
import excelBase.ExcelData;
import excelBase.Sheet;


public abstract class BaseOut
{
	String ENDL = "\r\n";
	
	protected boolean m_isAllowSet;
	protected String m_nameSpace;
	protected ArrayList<Sheet> m_referenceList;
	protected static StringBuffer m_tab = new StringBuffer("");
	protected static int m_streamPointer = 0;
	protected CodeOut m_codeOut;
	
	public BaseOut(boolean isAllowSet, String nameSpace, CodeOut co) throws ErrorException
	{
		m_isAllowSet = isAllowSet;
		m_nameSpace = nameSpace;
		m_codeOut = co;
		m_referenceList = ExcelData.getSheetSetByExcelType(ExcelType.E_REFERENCE_EXT, Config.NO_POSITION);
		if(m_referenceList.size() == 0)
		{
			new WarningHandler(WarningDefine.E_EMPTY_REFERENCE_WARNING, Config.NO_POSITION).showWarning();
		}
	}
		
	protected abstract StringBuffer outMember(ReferenceMember member, int tabNumber) throws ErrorException;
	
	protected abstract StringBuffer outMethod(ReferenceMember member, int tabNumber) throws ErrorException;
	
	protected StringBuffer outType(Type type, CodeOut co) throws ErrorException
	{
		StringBuffer out = new StringBuffer("");
		if(type.getChildren() == null)
		{
			if(type.getType() == ReferenceType.E_REFERENCE_RT && !hasReference(type.getText()))
			{
				new WarningHandler(WarningDefine.E_NO_REFERENCE_WARNING, type.getText(), Config.NO_FIND).showWarning();
			}
			String text = type.getType().getJCodeValue(co);
			if(text == null)
			{
				text = type.getText();
			}
			out.append(text);
		}
		else 
		{
			ReferenceExtraType ret = type.getExtraType();
			String foreText = ret.getCodeValue(co);
			if(foreText == null)
			{
				throw new ErrorException(ErrorDefine.E_LANGUAGE_NOT_SUPPORT_ERROR, ret.getErrorText(), Config.NO_POSITION);
			}
			Type[] children = type.getChildren();
			String childrenText = "";
			if(children.length == 1)
			{
				childrenText = outType(children[0], co).toString();
			}
			else
			{
				childrenText = outType(children[0], co).toString() + ", " + outType(children[1], co);
			}
			out.append(outExtraType(ret, childrenText));
		}
		return out;
	}

	protected boolean hasReference(String name)
	{
		for(Sheet sheet: m_referenceList)
		{
			if(sheet.getName().compareTo(name) == 0)
			{
				return true;
			}
		}
		return false;
	}
	
	protected abstract StringBuffer outExtraType(ReferenceExtraType ret, String childrenText) throws ErrorException;
	
	protected abstract StringBuffer outClass(ReferenceClass rc) throws ErrorException;
	
	public abstract void save(String path, int position) throws ErrorException;
	
	protected void saveToFile(String path, StringBuffer text, int position) throws ErrorException
	{
		text = format(text, m_codeOut);
		BufferedWriter writer = null;
		try 
		{
			FileOutputStream fos = new FileOutputStream(path);
			writer = new BufferedWriter(new OutputStreamWriter(fos));
			writer.write(text.toString());
			writer.flush();
		} 
		catch(Exception e) 
		{
			throw new ErrorException(ErrorDefine.E_CANT_WRITE_CODE_ERROR, path, position);
		}
		finally
		{
			if(writer != null)
			{
				try
				{
					writer.close();
				} 
				catch(Exception e2) 
				{
				}
			}
		}
	}
	
	protected StringBuffer format(StringBuffer input, CodeOut co)
	{
		m_streamPointer = 0;
		m_tab = new StringBuffer("");
		StringBuffer out = new StringBuffer("");
		String line = getLine(input);
		while(line != null)
		{
			if(line.compareTo(Config.CODE_INDENT_START) == 0)
			{
				out.append(m_tab);
				out.append(line);
				addTab();
			}
			else if(line.compareTo(Config.CODE_INDENT_END) == 0)
			{
				subTab();
				out.append(m_tab);
				out.append(line);
			}
			else
			{
				if(co == CodeOut.E_CPP_CO && line.length() != 0 && line.charAt(line.length() - 1) == Config.CPP_NO_INDENT)
				{
					String tab = m_tab.substring(1);
					out.append(tab);
					out.append(line);
				}
				else
				{
					out.append(m_tab);
					out.append(line);
				}
			}
			out.append(ENDL);
			line = getLine(input);
		}
		return out;
	}
	
	protected String getLine(StringBuffer input)
	{
		int end = input.length();
		if(m_streamPointer >= end)
		{
			return null;
		}
		int start = m_streamPointer;
		m_streamPointer = input.indexOf(ENDL, start);
		if(m_streamPointer == -1)
		{
			m_streamPointer = end;
		}
		else
		{
			end = m_streamPointer;
			m_streamPointer += ENDL.length();
		}
		return input.substring(start, end);
	}
	
	protected void addTab()
	{
		m_tab.append('\t');
	}
	
	protected void subTab()
	{
		if(m_tab.length() < 1)
		{
			return;
		}
		m_tab.deleteCharAt(m_tab.length() - 1);
	}
}
